#include "ui_element.h"

#include <fstream>

#include "game.h"

void UIElementTank::OnKey(Game &game, int32_t key, int32_t action, int32_t mode)
{
    if (key == GLFW_KEY_W && action == GLFW_PRESS) {
        accelerate = SpeedUpAccelerate;
    } else if (key == GLFW_KEY_W && action == GLFW_RELEASE) {
        accelerate = 0;
    }

    if (key == GLFW_KEY_S && action == GLFW_PRESS) {
        accelerate = SpeedDownAccelerate;
    } else if (key == GLFW_KEY_S && action == GLFW_RELEASE) {
        accelerate = 0;
    }

    if (key == GLFW_KEY_A && action == GLFW_PRESS) {
        angleAccelerate = RotateLeftDownAccelerate;
    } else if (key == GLFW_KEY_A && action == GLFW_RELEASE) {
        angleAccelerate = 0;
    }

    if (key == GLFW_KEY_D && action == GLFW_PRESS) {
        angleAccelerate = RotateRightDownAccelerate;
    } else if (key == GLFW_KEY_D && action == GLFW_RELEASE) {
        angleAccelerate = 0;
    }
}

void UIElementTank::OnMouseButton(Game &game, int button, int action, int mods)
{
    lastMouseAction = action;
    lastMouseButton = button;

    if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS && currentCooldown <= 0) {
        auto s = (size - UIElementLoader::GetElement("Bullet0").size) / 2;
        auto bullet = std::make_shared<UIElementBullet>(
            UIElementLoader::GetElement("Bullet0"), x + s, y + s);

        bullet->speed += speed;
        double dx = lastMouseX - (x + size / 2);
        double dy = lastMouseY - (y + size / 2);
        double round = sqrt(dx * dx + dy * dy);
        if (round != 0) {
            dx /= round;
            dy /= round;
            auto rad = acos(dy);
            if (dx < 0) {
                rad = 2 * acos(-1) - rad;
            }
            bullet->angle = rad;
        }

        bullet->Init();
        game.elements.push_back(bullet);
        currentCooldown = fireCooldown;
    }
}

void UIElementTank::OnMousePosition(Game &game, int x, int y)
{
    lastMouseX = x;
    lastMouseY = y;
}

UIElementLoader::UIElementLoader(const char *filename)
{
    std::ifstream ifs(filename);
    ifs >> json;
    for (const auto &tank : json["tank"]) {
        elements[tank["name"]] = std::make_unique<UIElementTank>(
            tank["name"].get<std::string>().c_str(), tank["size"].get<int>(),
            tank["textureY"].get<int>(), tank["textureX"].get<int>(),
            tank["canDestroy"].get<bool>(), tank["canBlock"].get<bool>());
    }

    for (const auto &bullet : json["bullet"]) {
        elements[bullet["name"]] = std::make_unique<UIElementBullet>(
            bullet["name"].get<std::string>().c_str(), bullet["size"].get<int>(),
            bullet["textureY"].get<int>(), bullet["textureX"].get<int>(),
            bullet["canDestroy"].get<bool>(), bullet["canBlock"].get<bool>());
    }

    for (const auto &wall : json["wall"]) {
        elements[wall["name"]] = std::make_unique<UIElement>(
            wall["name"].get<std::string>().c_str(), wall["size"].get<int>(),
            wall["textureY"].get<int>(), wall["textureX"].get<int>(),
            wall["canDestroy"].get<bool>(), wall["canBlock"].get<bool>());
    }
}

UIElement &UIElementLoader::GetElement(const std::string &name)
{
    if (ptr == nullptr) {
        ptr = new UIElementLoader("out/war_of_tank.json");
    }

    assert(ptr->elements.find(name) != ptr->elements.end());
    return *ptr->elements[name];
}
